
#ifndef _REF_PTR_IMPL_
#define _REF_PTR_IMPL_

#include <memory>
#include "Utility/Interlocked.h"
#include "Utility/TemplateImpl/DummyTypeDef.h"

namespace nebula { namespace utility {

template<typename TP>
class refptr_count_base;

template<>
class refptr_count_base<single_thread>
{
public:
	explicit refptr_count_base() : _usecount(1)
	{
	}

	void addref()
	{
		++_usecount;
	}

	void release()
	{
		if(--_usecount == 0) {
			this->dispose();
			delete this;
		}
	}

	long use_count()
	{
		return _usecount;
	}

	virtual void dispose() =0 ;
	virtual ~refptr_count_base(){};

private:
	long _usecount;
};

template<>
class refptr_count_base<multi_thread>
{
public:
	explicit refptr_count_base() : _usecount(1)
	{
	}

	void addref()
	{
		InterlockedIncrement(&_usecount);
	}

	void release()
	{
		const long usecount = InterlockedDecrement(&_usecount);
		if (usecount == 0)
		{
			this->dispose();
			delete this;
		}
	}

	long use_count()
	{
		return _usecount;
	}

	virtual void dispose() =0 ;
	virtual ~refptr_count_base(){};

private:
	long _usecount;
};

template<typename T, typename TP>
class refptr_count_impl : public refptr_count_base<TP> {
public:
	explicit refptr_count_impl(T* p) : px(p)
	{
	}

	virtual void dispose()
	{
		if(px)
			delete px;
	}

private:
	T* px;
};

template<typename T, typename D, typename TP>
class refptr_count_impld : public refptr_count_base<TP>{
public:
	explicit refptr_count_impld(T* p, D d) : px(p), del(d)
	{
	}

	virtual void dispose()
	{
		del(px);
	}

private:
	T* px;
	D  del;
};

template<typename ThreadPolicy>
class refptr_count {
private:
	refptr_count_base<ThreadPolicy>* _pi;

public:
	explicit refptr_count() : _pi(0)
	{
	}

	template<typename Y>
	explicit refptr_count(Y *p)
	{
		_pi = new refptr_count_impl<Y, ThreadPolicy>(p);
	}

	template<typename Y, typename D>
	explicit refptr_count(Y *p, D d)
	{
		_pi = new refptr_count_impld<Y, D, ThreadPolicy>(p, d);
	}

	~refptr_count()
	{
		if (_pi) _pi->release();
	}

	refptr_count& operator=(refptr_count<ThreadPolicy> const &other)
	{
		if (_pi != other._pi) {
			if (_pi)
				_pi->release();
			_pi = other._pi;
			if (_pi)
				_pi->addref();
		}
		return *this;
	}

	explicit refptr_count(refptr_count<ThreadPolicy> const &other): _pi(other._pi)
	{
		if (_pi)
			_pi->addref();
	}

	long use_count() const
	{
		return _pi != 0 ? _pi->use_count() : 0;
	}

	void swap(refptr_count & other)
	{
		std::swap(_pi, other._pi);
	}
};

}} // namespace nebula::utility

#endif
